//--------------------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------------------
cbuffer CB : register( b0 )
{
    matrix      g_mWorldViewProjection;
    float4      g_vOutputColor;
};

//--------------------------------------------------------------------------------------
// Textures and Samplers
//--------------------------------------------------------------------------------------
Texture2D   g_txDiffuse : register( t0 );
SamplerState g_samLinear : register( s0 );

//--------------------------------------------------------------------------------------
// Input / Output structures
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
	float4 vCP	: CP;
    float4 vSP  : SP;
};

struct VS_OUTPUT
{
    float4 vCP  : CP;
    float4 vSP  : SP;
};

struct HS_CONSTANT_DATA_OUTPUT
{
    float Edges[4]   : SV_TessFactor;
    float Inside[2]  : SV_InsideTessFactor;
};

struct HS_OUTPUT
{
    float4 vCP  : CP;
    float4 vSP  : SP;
};

struct DS_OUTPUT
{
    float4 vPosition : SV_POSITION;
    float2 vTexcoord : TEXCOORD0;
};

//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
VS_OUTPUT VSMain( VS_INPUT Input )
{	
	VS_OUTPUT Out;
	Out.vCP = mul( Input.vCP, g_mWorldViewProjection );
    Out.vSP = mul( Input.vSP, g_mWorldViewProjection );
	return Out;
}

//--------------------------------------------------------------------------------------
// Hull Shader
//--------------------------------------------------------------------------------------
#define INPUT_PATCH_SIZE 4
#define OUTPUT_PATCH_SIZE 4

#ifndef TESS_AMOUNT
#define TESS_AMOUNT 1
#endif //TESS_AMOUNT

HS_CONSTANT_DATA_OUTPUT ConstantHS( InputPatch<VS_OUTPUT, INPUT_PATCH_SIZE> ip,
                                          uint PatchID : SV_PrimitiveID )
{    
    HS_CONSTANT_DATA_OUTPUT Output;

    Output.Inside[0] = Output.Edges[1] = Output.Edges[3] = TESS_AMOUNT;
	Output.Inside[1] = Output.Edges[0] = Output.Edges[2] = 2;
    
    return Output;
}


//integer
//fractional_even
//fractional_odd
//--------------------------------------------------------------------------------------
[domain("quad")]
[partitioning("integer")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(OUTPUT_PATCH_SIZE)]
[patchconstantfunc("ConstantHS")]
HS_OUTPUT HSMain( InputPatch<VS_OUTPUT, INPUT_PATCH_SIZE> p, 
                    uint i : SV_OutputControlPointID,
                    uint PatchID : SV_PrimitiveID )
{
    HS_OUTPUT Output;
    Output.vCP = p[i].vCP;
    Output.vSP = p[i].vSP; 
    return Output;
}


//--------------------------------------------------------------------------------------
// Domain Shader
//--------------------------------------------------------------------------------------
float4 BernsteinBasis(float t)
{
    float invT = 1.0f - t;

    return float4( invT * invT * invT,
                   3.0f * t * invT * invT,
                   3.0f * t * t * invT,
                   t * t * t );
}


//--------------------------------------------------------------------------------------
float4 EvaluateBezier( const OutputPatch<HS_OUTPUT, OUTPUT_PATCH_SIZE> bezpatch,
                       float4 BasisU,
                       float2 BasisV )
{
    float4 Value = float4(0,0,0,0);

    Value  = BasisV.x * ( 
            bezpatch[0].vSP * BasisU.x + 
            bezpatch[0].vCP * BasisU.y + 
            bezpatch[2].vCP * BasisU.z + 
            bezpatch[2].vSP * BasisU.w );

    Value += BasisV.y * ( 
            bezpatch[1].vSP * BasisU.x + 
            bezpatch[1].vCP * BasisU.y + 
            bezpatch[3].vCP * BasisU.z + 
            bezpatch[3].vSP * BasisU.w );
    
    return Value;
}


[domain("quad")]
DS_OUTPUT DSMain( HS_CONSTANT_DATA_OUTPUT input, 
                    float2 UV : SV_DomainLocation,
                    const OutputPatch<HS_OUTPUT, OUTPUT_PATCH_SIZE> bezpatch )
{
    float4 BasisU = BernsteinBasis( UV.x );
    float2 LinearV = float2(UV.y, 1 - UV.y);

    float4 WorldPos = EvaluateBezier( bezpatch, BasisU, LinearV );

    DS_OUTPUT Output;

	Output.vPosition = WorldPos;
    Output.vTexcoord = UV;
    
    return Output;    
}

//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PSMain( DS_OUTPUT Input ) : SV_TARGET
{
    #ifdef TEXTURE   
	   return g_vOutputColor * g_txDiffuse.Sample( g_samLinear, Input.vTexcoord );
    #else
       return g_vOutputColor;
    #endif
}
/**/
